package br.requisiteworks.seguranca.modelo.dao.jpa;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import br.requisiteworks.modelo.Funcionario;
import br.requisiteworks.seguranca.modelo.Usuario;
import br.requisiteworks.seguranca.modelo.dao.UserDao;
import br.requisiteworks.util.persistencia.ErroBancoDados;
import br.requisiteworks.util.persistencia.ResultadoVazio;

@Repository
public class JpaUserDao implements UserDao {

	@PersistenceContext
	private EntityManager em;

	@Transactional(propagation = Propagation.REQUIRED)
	public void delete(Usuario user) throws ErroBancoDados {
		try {
			user.setRegistroAtivo(false);
			this.update(user);
		} catch (PersistenceException e) {
			throw new ErroBancoDados("Ocorreu um erro ao deletar usuario: "
					+ user, e);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void insert(Usuario user) throws ErroBancoDados {
		try {
			em.persist(user);
			em.flush();
		} catch (PersistenceException e) {
			throw new ErroBancoDados("Ocorreu um erro ao inserir usuario: "
					+ user, e);
		}
	}

	@Override
	public Usuario select(Funcionario funcionario) throws ResultadoVazio {
		TypedQuery<Usuario> selectUser = em
				.createQuery(
						"SELECT OBJECT(u) FROM Usuario u WHERE u.funcionario=:funcionario",
						Usuario.class);

		selectUser.setParameter("funcionario", funcionario);
		try {
			return selectUser.getSingleResult();
		} catch (NoResultException e) {
			throw new ResultadoVazio("Nao foi encontrado usuario numero = "
					+ funcionario.getNumero());
		}
	}

	@Override
	public List<Usuario> select() throws ResultadoVazio {
		TypedQuery<Usuario> selectUser = em.createQuery(
				"SELECT OBJECT(u) FROM Usuario u", Usuario.class);

		List<Usuario> usuarios = selectUser.getResultList();

		if (usuarios == null || usuarios.isEmpty()) {
			throw new ResultadoVazio(
					"Nao foi encontrados registros de usuarios ativos na base de dados");
		}

		return usuarios;
	}

	@Override
	public Usuario select(String username) throws ResultadoVazio {
		TypedQuery<Usuario> selectUser = em.createQuery(
				"SELECT OBJECT(u) FROM Usuario u WHERE u.username = :username",
				Usuario.class);

		selectUser.setParameter("username", username);
		try {
			Usuario user = selectUser.getSingleResult();

			return user;
		} catch (NoResultException e) {
			throw new ResultadoVazio(
					"Nao foi encontrado usuario com ativo com username = \""
							+ username + "\"");
		}
	}

	@Transactional(propagation = Propagation.REQUIRED)
	public void update(Usuario user) {
		em.merge(user);
		em.flush();
	}
}
